#ifndef TB_REFLECTION_CONTAINER_ITERATOR_HPP__
#define TB_REFLECTION_CONTAINER_ITERATOR_HPP__

#include <map>
#include <list>
#include <vector>

TB_NAMESPACE_BEGIN

namespace reflection {

struct  CollectionEnumer {
  virtual ~CollectionEnumer() {};
  virtual CollectionEnumerPtr Create(const void* val) const = 0;
  virtual bool HasNext() const = 0;
  virtual uint32 Size() const = 0;
  virtual Variant Next() = 0;
  virtual void Clear() = 0;
  virtual void Append(const Variant& val) = 0;
  virtual bool IsPairType() const { return false; }
  virtual bool IsMapType() const { return false; }
  virtual bool IsSetType() const { return false; }
  virtual bool IsArrayType() const { return false; }
  virtual bool IsFiexedSize() const { return false; }
  virtual bool SupportRandommAccess() const { return false; }
  virtual Variant Get(uint32 index) const { (void)index; return Variant(); }
  virtual void Set(uint32 index, const Variant &val) { (void)index; (void)val; }
};

template <typename _KeyT, typename _ValueT>
struct StdPairIterator : public CollectionEnumer {
  typedef _STD pair<_KeyT, _ValueT> collection_type;
  StdPairIterator(const void* val) : visited_(false) {
    v_ = static_cast<collection_type*>(const_cast<void*>(val));
  }

  CollectionEnumerPtr Create(const void* val) const OVERRITE {
    return make_shared<StdPairIterator<_KeyT, _ValueT> >(val);
  }

  bool HasNext() const OVERRITE {
    return !visited_;
  }

  uint32 Size() const OVERRITE {
    return 1;
  }

  Variant Next() OVERRITE {
    visited_ = true;
    return Variant::FromValue(*v_);
  }

  void Append(const Variant& val) OVERRITE{
    *v_ = val.Value<collection_type>();
  }

  bool IsPairType() const OVERRITE { return true; }

private:
  collection_type *v_;
  bool visited_;
};

template <typename T, uint32 N>
struct TrivalArrayIterator : public CollectionEnumer {
  // zero length array is invalid
  BOOST_STATIC_ASSERT(N > 0);

  typedef T element_type;

  typedef element_type* container_type;

  typedef element_type* iterator_type;

  TrivalArrayIterator() {}

  TrivalArrayIterator(const void* val) : index_(0) {
    v_ = static_cast<container_type>(const_cast<void*>(val));
    it_ = v_;
  }

  CollectionEnumerPtr Create(const void* val) const OVERRITE{
    return make_shared<TrivalArrayIterator<T, N> >(val);
  }

  bool HasNext() const OVERRITE{
    return it_ != v_ + N;
  }

  uint32 Size() const OVERRITE{
    return N;
  }

  Variant Next() OVERRITE{
    return Variant::FromValue(*(it_++));
  }

  void Append(const Variant& val) OVERRITE{
    if (index_ < N) {
      *(v_ + index_++) = val.Value<T>();
    } else {
      LWARNING() << "index_ is more than array capacity";
    }
  }

  Variant Get(uint32 index) const OVERRITE {
    TB_SMART_ASSERT(index < Size());
    return v_[index];
  }

  void Set(uint32 index, const Variant &val) OVERRITE {
    TB_SMART_ASSERT(index < Size());
    v_[index] = val;
  }

  bool IsArrayType() const OVERRITE { return true; }

  bool IsFiexedSize() const OVERRITE { return true; }

private:
  container_type v_;
  iterator_type it_;
  uint32 index_;
};

template <typename T, typename A, typename C>
struct SequenceIterator : public CollectionEnumer {
  typedef C container_type;

  typedef typename C::iterator iterator_type;

  SequenceIterator() {}

  SequenceIterator(const void* val) {
    v_ = static_cast<container_type*>(const_cast<void*>(val));
    it_ = v_->begin();
  }

  CollectionEnumerPtr Create(const void* val) const OVERRITE{
    return make_shared<SequenceIterator<T, A, C> >(val);
  }

  bool HasNext() const OVERRITE{
    return it_ != v_->end();
  }

  uint32 Size() const OVERRITE{
    return (uint32)v_->size();
  }

  Variant Next() OVERRITE{
    return Variant::FromValue(*(it_++));
  }

  void Clear() OVERRITE {
    v_->clear();
  }

  void Append(const Variant& val) OVERRITE{
    v_->push_back(val.Value<T>());
  }

  bool IsArrayType() const OVERRITE { return true; }

  bool SupportRandommAccess() const OVERRITE { return false; }

private:
  container_type* v_;
  iterator_type it_;
};

template <typename T, typename A, typename C>
struct RandomAccessSequenceIterator : public CollectionEnumer {
  typedef C container_type;

  typedef typename C::iterator iterator_type;

  RandomAccessSequenceIterator() {}

  RandomAccessSequenceIterator(const void* val) {
    v_ = static_cast<container_type*>(const_cast<void*>(val));
    it_ = v_->begin();
  }

  CollectionEnumerPtr Create(const void* val) const OVERRITE {
    return make_shared<RandomAccessSequenceIterator<T, A, C> >(val);
  }

  bool HasNext() const OVERRITE {
    return it_ != v_->end();
  }

  uint32 Size() const OVERRITE {
    return (uint32)v_->size();
  }

  Variant Next() OVERRITE {
    return Variant::FromValue(*(it_++));
  }

  void Clear() OVERRITE {
    v_->clear();
  }

  void Append(const Variant& val) OVERRITE {
    v_->push_back(val.Value<T>());
  }

  Variant Get(uint32 index) const OVERRITE {
    TB_SMART_ASSERT(index < Size());
    return Variant::FromValue((*v_)[index]);
  }

  void Set(uint32 index, const Variant &val) OVERRITE {
    TB_SMART_ASSERT(index < Size());
    (*v_)[index] = val.Value<T>();
  }

  bool IsArrayType() const OVERRITE { return true; }

  bool SupportRandommAccess() const OVERRITE { return true; }

private:
  container_type* v_;
  iterator_type it_;
};

template <typename _Kty, typename _Ty, typename _Pr, typename _Alloc>
struct StdMapIterator : public CollectionEnumer {
  typedef _STD map<_Kty, _Ty, _Pr, _Alloc> container_type;

  typedef typename container_type::iterator iterator_type;

  typedef _STD pair<_Kty, _Ty> pair_type;;

  StdMapIterator() {}

  StdMapIterator(const void* val) {
    v_ = static_cast<container_type*>(const_cast<void*>(val));
    it_ = v_->begin();
  }

  CollectionEnumerPtr Create(const void* val) const OVERRITE{
    return make_shared<StdMapIterator<_Kty, _Ty, _Pr, _Alloc> >(val);
  }

  bool HasNext() const OVERRITE{
    return it_ != v_->end();
  }

  uint32 Size() const OVERRITE{
    return (uint32)v_->size();
  }

  void Clear() OVERRITE {
    v_->clear();
  }

  Variant Next() OVERRITE{
    pair_type pr = *(it_++);
    return Variant::FromValue(std::make_pair(pr.first, pr.second));
  }

  void Append(const Variant& val) OVERRITE{
    pair_type pv = val.Value<pair_type>();
    v_->insert(pv);
  }

  bool IsMapType() const OVERRITE { return true; }

private:
  container_type* v_;
  iterator_type it_;
};


template <typename T>
struct MakeContainerIteratorImpl {
  static CollectionEnumer* Make() {
    return nullptr;
  }
};

template <typename _KeyT, typename _ValueT>
struct MakeContainerIteratorImpl < _STD pair<_KeyT, _ValueT> > {
  static CollectionEnumer* Make() {
    return new StdPairIterator<_KeyT, _ValueT>();
  }
};

template <typename T, uint32 N>
struct MakeContainerIteratorImpl < T[N] > {
  static CollectionEnumer* Make() {
    return new TrivalArrayIterator<T, N>();
  }
};

template <typename T, typename A>
struct MakeContainerIteratorImpl < _STD vector<T, A> > {
  static CollectionEnumer* Make() {
    return new RandomAccessSequenceIterator<T, A, _STD vector<T, A> >();
  }
};

template <typename T, typename A>
struct MakeContainerIteratorImpl < _STD list<T, A> > {
  static CollectionEnumer* Make() {
    return new SequenceIterator<T, A, _STD list<T, A> >();
  }
};

template <typename _Kty, typename _Ty, typename _Pr, typename _Alloc>
struct MakeContainerIteratorImpl < _STD map<_Kty, _Ty, _Pr, _Alloc> > {
  static CollectionEnumer* Make() {
    return new StdMapIterator<_Kty, _Ty, _Pr, _Alloc>();
  }
};

template <typename T>
CollectionEnumer* MakeContainerIterator() {
  return MakeContainerIteratorImpl<T>::Make();
}

} // namespace reflection

TB_NAMESPACE_END

#endif // TB_REFLECTION_CONTAINER_ITERATOR_HPP__
